//
//  TweetImageStore.m
//  Guazi
//
//  Created by koolearn on 11-8-2.
//  Copyright 2011年 __MyCompanyName__. All rights reserved.
//

#import <sqlite3.h>
#import "TweetImageStore.h"
#import "ImageDownloader.h"
#import "DBConnection.h"
#import "Statement.h"
#import "ImageUtils.h"

#define MAX_CONNECTION 5

@interface TweetImageStore (private) 
- (void)getPendingImage:(ImageDownloader*)sender;
- (UIImage*) getImageFromDB:(NSString*)url;
- (void) insertImage:(NSData*)image forURL:(NSString*)url;
+ (UIImage*) defaultProfileImage:(CGFloat)size;
@end

@implementation TweetImageStore

#pragma mark - init & destroy methods

static TweetImageStore* sharedInstance;

+ (TweetImageStore*) sharedInstance
{
	@synchronized(self) {
		if ( sharedInstance == nil ) {
			sharedInstance = [[TweetImageStore alloc] init];
		}
		return sharedInstance;
	}
}

- (id)init
{
	self = [super init];
    images    = [[NSMutableDictionary dictionary] retain];
    pending   = [[NSMutableDictionary dictionary] retain];
    delegates = [[NSMutableDictionary dictionary] retain];
    return self;
}

- (void)dealloc
{
    [delegates release];
    [pending release];
    [images release];
	[super dealloc];
}


#pragma mark - download image methods

- (UIImage*) getTweetImage:(NSString*)url square:(CGFloat)len delegate:(id)delegate
{
    CGSize size = CGSizeMake(len, len);
    return [self getTweetImage:url size:size delegate:self];
}


- (UIImage*) getTweetImage:(NSString*)url size:(CGSize)size delegate:(id)delegate
{
    if ( url == nil ) {
        return [TweetImageStore defaultProfileImage:size.width];
    }
	
    UIImage *image = [images objectForKey:url];
    if (image) return image;
    
    image = [self getImageFromDB:url];
    if (image) {
        UIImage* resizeImage = [image resizeImageInSize:size];
        if ( resizeImage != image ) {
            image = resizeImage;
            NSData *jpeg = UIImageJPEGRepresentation(image, 0.8);
            [self insertImage:jpeg forURL:url];
        }
        [images setObject:image forKey:url];
        return image;
    }
    
    ImageDownloader *dl = [pending objectForKey:url];
    if (dl == nil) {
        dl = [[[ImageDownloader alloc] initWithDelegate:self] autorelease];
        dl.context = [NSArray arrayWithObjects:[NSNumber numberWithFloat:size.width], [NSNumber numberWithFloat:size.height], nil];
        [pending setObject:dl forKey:url];
    }
    
    NSMutableArray *arr = [delegates objectForKey:url];
    if (arr) {
        [arr addObject:delegate];
    }
    else {
        [delegates setObject:[NSMutableArray arrayWithObject:delegate] forKey:url];
    }
    
    if ([pending count] <= MAX_CONNECTION && dl.requestURL == nil) {
        [dl get:url];
    }
    
    return [TweetImageStore defaultProfileImage:size.width];
}


- (void)getPendingImage:(ImageDownloader*)sender
{
    [pending removeObjectForKey:sender.requestURL];
    
    NSArray *keys = [pending allKeys];
    
    for (NSString *url in keys) {
        ImageDownloader *dl = [pending objectForKey:url];
        
        NSMutableArray *arr = [delegates objectForKey:url];
        if (arr == nil) {
            [pending removeObjectForKey:url];
        }
        else if ([arr count] == 0) {
            [delegates removeObjectForKey:url];
            [pending removeObjectForKey:url];
        }
        else {
            if (dl.requestURL == nil) {
                [dl get:url];
                break;
            }
        }
    }
}


static UIImage *sProfileImage = nil;

+(UIImage*)defaultProfileImage:(CGFloat)imageSize
{
    if (sProfileImage == nil) {
        //sProfileImage = [[UIImage imageNamed:@"profileImage.png"] retain];
        sProfileImage = [[UIImage imageNamed:@"user_default_photo.png"] retain];
    }
    return sProfileImage;
}



#pragma mark - ImageDownloader Delegate

- (void)imageDownloaderDidSucceed:(ImageDownloader*)sender
{
	UIImage *image = [UIImage imageWithData:sender.buf];
    
    if (image) {
        NSArray* array = (NSArray*) sender.context;
        NSNumber* width = [array objectAtIndex:0];
        NSNumber* height = [array objectAtIndex:1];
        CGSize size = CGSizeMake([width floatValue], [height floatValue]);
        image = [image resizeImageInSize:size];
        [self insertImage:sender.buf forURL:sender.requestURL];
        
        NSMutableArray *arr = [delegates objectForKey:sender.requestURL];
        if (arr) {
            for (id delegate in arr) {
                if ([delegate respondsToSelector:@selector(imageDidGetNewImage:forURL:)]) {
                    [delegate performSelector:@selector(imageDidGetNewImage:forURL:) withObject:image withObject:sender.requestURL];
                }
            }
            [delegates removeObjectForKey:sender.requestURL];
        }
        [images setObject:image forKey:sender.requestURL];
    }
    
    [self getPendingImage:sender];
}


- (void)imageDownloaderDidFail:(ImageDownloader*)sender error:(NSError*)error
{
    [self getPendingImage:sender];
}


#pragma mark - database operation methods

- (UIImage*)getImageFromDB:(NSString*)url
{
    UIImage *image = nil;
	
	sqlite3* theDatabase = [DBConnection getDatabase];
	char* sql = "SELECT image FROM images WHERE url=?";
	Statement* stmt = [[Statement alloc] initWithDB:theDatabase sql:sql];
    
    // Note that the parameters are numbered from 1, not from 0.
    [stmt bindString:url forIndex:1];
    if ([stmt step] == SQLITE_ROW) {
        // Restore image from Database
        NSData *data = [stmt getData:0];
        image = [UIImage imageWithData:data];
    }
    [stmt release];
    
	return image;
}


- (void)insertImage:(NSData*)buf forURL:(NSString*)url
{ 
	sqlite3* theDatabase = [DBConnection getDatabase];
	char* sql = "REPLACE INTO images VALUES(?, ?, DATETIME('now'))";
    Statement* stmt = [[Statement alloc] initWithDB:theDatabase sql:sql];
    [stmt bindString:url forIndex:1];
    [stmt bindData:buf forIndex:2];
    
    // Ignore error
    [stmt step];
    [stmt release];
}

@end
